package com.sourceQ.system.service.message.sms.impl;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sourceQ.common.core.constant.message.CommonStatusEnum;
import com.sourceQ.common.core.utils.bean.BeanUtils;
import com.sourceQ.common.sms.core.client.SmsClient;
import com.sourceQ.common.sms.core.client.dto.SmsTemplateRespDTO;
import com.sourceQ.common.sms.core.enums.SmsTemplateAuditStatusEnum;
import com.sourceQ.system.domain.message.sms.SysSmsChannel;
import com.sourceQ.system.domain.message.sms.SysSmsTemplate;
import com.sourceQ.system.dto.message.SmsTemplatePageReqDTO;
import com.sourceQ.system.dto.message.SmsTemplateSaveReqDTO;
import com.sourceQ.system.mapper.message.sms.SysSmsTemplateMapper;
import com.sourceQ.system.service.message.sms.SysSmsChannelService;
import com.sourceQ.system.service.message.sms.SysSmsTemplateService;
import com.sourceQ.system.vo.sms.SmsTemplateVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;

import static com.sourceQ.common.core.constant.ErrorCodeConstants.*;
import static com.sourceQ.common.core.utils.ExceptionUtil.exception;

/**
 * @author: SourceQ
 * @create: 2024-04-24 11:26
 * @Description:
 */
@Service
@Slf4j
public class SysSmsTemplateServiceImpl extends ServiceImpl<SysSmsTemplateMapper, SysSmsTemplate> implements SysSmsTemplateService {
    /**
     * 正则表达式，匹配 {} 中的变量
     */
    private static final Pattern PATTERN_PARAMS = Pattern.compile("\\{(.*?)}");
    @Autowired
    @Lazy
    private SysSmsChannelService channelService;
    @Override
    public Long createSmsTemplate(SmsTemplateSaveReqDTO createReqVO) {
        SysSmsChannel sysSmsChannel = validateSmsChannel(createReqVO.getChannelId());
        // 校验短信编码是否重复
        validateSmsTemplateCodeDuplicate(null, createReqVO.getCode());
        // 校验短信模板
        validateApiTemplate(createReqVO.getChannelId(), createReqVO.getApiTemplateId());

        // 插入
        SysSmsTemplate template = BeanUtils.toBean(createReqVO, SysSmsTemplate.class);
        template.setParams(parseTemplateContentParams(template.getContent()));
        template.setChannelCode(sysSmsChannel.getCode());
        baseMapper.insert(template);
        // 返回
        return template.getId();
    }

    @Override
    public void updateSmsTemplate(SmsTemplateSaveReqDTO updateReqVO) {
        // 校验存在
        validateSmsTemplateExists(updateReqVO.getId());
        // 校验短信渠道
        SysSmsChannel channel = validateSmsChannel(updateReqVO.getChannelId());
        // 校验短信编码是否重复
        validateSmsTemplateCodeDuplicate(updateReqVO.getId(), updateReqVO.getCode());
        // 校验短信模板
        validateApiTemplate(updateReqVO.getChannelId(), updateReqVO.getApiTemplateId());

        // 更新
        SysSmsTemplate updateObj = BeanUtils.toBean(updateReqVO, SysSmsTemplate.class);
        updateObj.setParams(parseTemplateContentParams(updateObj.getContent()));
        updateObj.setChannelCode(channel.getCode());
        baseMapper.updateById(updateObj);
    }

    @Override
    public void deleteSmsTemplate(Long id) {
        // 校验存在
        validateSmsTemplateExists(id);
        baseMapper.deleteById(id);
    }

    @Override
    public SysSmsTemplate getSmsTemplate(Long id) {
        return baseMapper.selectById(id);
    }

    @Override
    public SysSmsTemplate getSmsTemplateByCodeFromCache(String code) {
        return baseMapper.selectOne(Wrappers.<SysSmsTemplate>lambdaQuery().eq(SysSmsTemplate::getCode,code));
    }

    @Override
    public IPage<SmsTemplateVo> getSmsTemplatePage(Page page, SmsTemplatePageReqDTO pageReqVO) {
        IPage<SmsTemplateVo> pageVo = baseMapper.page(page, pageReqVO);
        return pageVo;
    }

    @Override
    public Long getSmsTemplateCountByChannelId(Long channelId) {
        return baseMapper.selectCount(new LambdaQueryWrapper<SysSmsTemplate>().eq(SysSmsTemplate::getChannelId,channelId));
    }

    @Override
    public String formatSmsTemplateContent(String content, Map<String, Object> params) {
        return StrUtil.format(content, params);
    }

    /**
     * 校验短信模版
     * @param id
     */
    private void validateSmsTemplateExists(Long id) {
        if (baseMapper.selectById(id) == null) {
            throw exception(SMS_TEMPLATE_NOT_EXISTS);
        }
    }

    /**
     * 校验短信渠道
     * @param channelId
     * @return
     */
    public SysSmsChannel validateSmsChannel(Long channelId){
        SysSmsChannel channel = channelService.getSmsChannel(channelId);
        if (channel == null) {
            throw exception(SMS_CHANNEL_NOT_EXISTS);
        }
        if (CommonStatusEnum.isDisable(channel.getStatus())) {
            throw exception(SMS_CHANNEL_DISABLE);
        }
        return channel;
    }

    /**
     * 根据code校验模版是否重复
     * @param id id为空说明是新建，不为空说明是修改,
     * @param code
     */
    public void validateSmsTemplateCodeDuplicate(Long id, String code){
        SysSmsTemplate template = baseMapper.selectOne(Wrappers.<SysSmsTemplate>lambdaQuery().eq(SysSmsTemplate::getCode, code));
        if (template==null){
            return;
        }
        //如果id为空，但是根据code能查出模板，说明该条新增数据重复了;如果id不为空，但是查出的模版id也不相等，说明也是有重复数据
        if (id==null||!template.equals(id)){
            throw exception(SMS_TEMPLATE_CODE_DUPLICATE, code);
        }

    }
    /**
     * 校验 API 短信平台的模板是否有效
     *
     * @param channelId 渠道编号
     * @param apiTemplateId API 模板编号
     */
    private void validateApiTemplate(Long channelId, String apiTemplateId) {
        SmsClient smsClient = channelService.getSmsClient(channelId);
        Assert.notNull(smsClient, String.format("短信客户端(%d) 不存在", channelId));
        SmsTemplateRespDTO template;
        try {
            template = smsClient.getSmsTemplate(apiTemplateId);
        } catch (Throwable ex) {
            throw exception(SMS_TEMPLATE_API_ERROR, ExceptionUtil.getRootCauseMessage(ex));
        }
        // 校验短信模版
        if (template == null) {
            throw exception(SMS_TEMPLATE_API_NOT_FOUND);
        }
        if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.CHECKING.getStatus())) {
            throw exception(SMS_TEMPLATE_API_AUDIT_CHECKING);
        }
        if (Objects.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.FAIL.getStatus())) {
            throw exception(SMS_TEMPLATE_API_AUDIT_FAIL, template.getAuditReason());
        }
        Assert.equals(template.getAuditStatus(), SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
                String.format("短信模板(%s) 审核状态(%d) 不正确", apiTemplateId, template.getAuditStatus()));
    }

    /**
     * 模版做正则匹配
     * @param content
     * @return
     */
    private List<String> parseTemplateContentParams(String content) {
        return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
    }
}
